﻿using KGySoft.CoreLibraries;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KalevaAalto.CollectionPart
{
    public interface ITwoWayDictionary<T1, T2> :ICollection<KeyValuePair<T1,T2>> where T1 : notnull where T2 : notnull
    {
        public void Add(T1 first,T2 second);
        public T2 GetValueByFirst(T1 value);
        public T1 GetValueBySecond(T2 value);

        public T2 GetValueByFirst(T1 value, T2 defaultValue);
        public T1 GetValueBySecond(T2 value, T1 defaultValue);
        public bool RemoveByFirst(T1 value);
        public bool RemoveBySecond(T2 value);

        public bool ContainsFirst(T1 value);
        public bool ContainsSecond(T2 value);


        
    }


    public class TwoWayDictionary<T1, T2> : ITwoWayDictionary<T1, T2> where T1 : notnull where T2 : notnull
    {
        private IDictionary<T1, T2> _dictionaryLeft = new Dictionary<T1, T2>();
        private IDictionary<T2,T1> _dictionaryRight = new Dictionary<T2, T1>();

        public int Count => _dictionaryLeft.Count;

        public bool IsReadOnly => false;

        public void Add(KeyValuePair<T1, T2> item)
        {
            _dictionaryLeft.Add(item.Key, item.Value);
            _dictionaryRight.Add(item.Value,item.Key);
        }

        public void Clear()
        {
            _dictionaryLeft.Clear();
            _dictionaryRight.Clear();
        }

        public bool Contains(KeyValuePair<T1, T2> item)
        {
            return _dictionaryLeft.Contains(item);
        }

        public bool ContainsFirst(T1 value)
        {
            return _dictionaryLeft.ContainsKey(value);
        }

        public bool ContainsSecond(T2 value)
        {
            return _dictionaryRight.ContainsKey(value);
        }


        public void CopyTo(KeyValuePair<T1, T2>[] array, int arrayIndex)
        {
            _dictionaryLeft.CopyTo(array,arrayIndex);
            _dictionaryRight.CopyTo(array.Select(it => new KeyValuePair<T2, T1>(it.Value, it.Key)).ToArray(), arrayIndex);
        }

        

        public T2 GetValueByFirst(T1 value)
        {
            return _dictionaryLeft[value];
        }

        public T1 GetValueBySecond(T2 value)
        {
            return _dictionaryRight[value];
        }


        public T2 GetValueByFirst(T1 value,T2 defalutValue)
        {
            return _dictionaryLeft.GetActualValueOrDefault(value, defalutValue);
        }

        public T1 GetValueBySecond(T2 value, T1 defalutValue)
        {
            return _dictionaryRight.GetActualValueOrDefault(value, defalutValue);
        }



        public bool Remove(KeyValuePair<T1, T2> item)
        {
            if (!Contains(item)) return false;
            _dictionaryLeft.Remove(item.Key);
            _dictionaryRight.Remove(item.Value);
            return true;
        }

        public bool RemoveByFirst(T1 value)
        {
            if (!_dictionaryLeft.ContainsKey(value)) return false;
            T2 s = _dictionaryLeft[value];
            _dictionaryLeft.Remove(value);
            _dictionaryRight.Remove(s);
            return true;
        }

        public bool RemoveBySecond(T2 value)
        {
            if (!_dictionaryRight.ContainsKey(value)) return false;
            T1 s = _dictionaryRight[value];
            _dictionaryRight.Remove(value);
            _dictionaryLeft.Remove(s);
            return true;
        }

        public IEnumerator<KeyValuePair<T1, T2>> GetEnumerator()
        {
            return _dictionaryLeft.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void Add(T1 first, T2 second) => Add(new KeyValuePair<T1, T2>(first,second));

        
    }
}
